package com.xjggb.characteristic;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.locks.ReentrantLock;

public class CreateAtomicity {

    private static int count;
    private static AtomicInteger count1 = new AtomicInteger(0);
    private static ReentrantLock lock = new ReentrantLock();
    static ThreadLocal tl1 = new ThreadLocal();
    static ThreadLocal tl2 = new ThreadLocal();

    public static void increment(){
        count++;
    }

    public static void increment1()  {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }


    }



    public static void main(String[] args) {
       show6();

    }

    public static void show6(){
    tl1.set("123");
    tl2.set("456");
        Thread thread1 = new Thread(() -> {
            System.out.println("count = " + tl1.get());
            System.out.println("count = " + tl2.get());
        });
        thread1.start();
        System.out.println("count = " + tl1.get());
        System.out.println("count = " + tl2.get());

    }

    public static void show5(){

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i <100 ; i++) {
                increment1();
            }
        });

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i <100 ; i++) {
                increment1();
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("count = " + count);

    }

    /*
    * ABA问题
    * */
    public static void show4(){
        AtomicStampedReference<String> reference = new AtomicStampedReference<>("a", 1);
        String reference1 = reference.getReference();
        int stamp = reference.getStamp();
        boolean b = reference.compareAndSet(reference1, "b", stamp, stamp + 1);
        System.out.println("修改的版本号1 " + b);
        boolean c = reference.compareAndSet("b", "c", 1, stamp + 1);
        System.out.println("修改的版本号2" + c);
    }
    /*
    * cas CAS只能保证对一个变量的操作是原子性的，无法实现对多行代码实现原子性
    ***ABA问题**：问题如下，可以引入版本号的方式，来解决ABA的问题。Java中提供了一个类在CAS时，针对各个版本追加版本号的操作。 AtomicStampeReference
    * */
    public static void show3(){
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                count1.incrementAndGet();
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                count1.incrementAndGet();
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("count = " + count1);

    }

    public static void show2(){

        synchronized (CreateAtomicity.class){
            Thread thread1 = new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    increment();
                }
            });
            Thread thread2 = new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    increment();
                }
            });
            thread1.start();
            thread2.start();
            try {
                thread1.join();
                thread2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("count = " + count);

        }


    }

    //多线程操作共享数据时，预期的结果，与最终的结果不符
    public static void show1(){
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                increment();
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                increment();
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("count = " + count);

    }

}
